package com.atguigu.gmall.activity.service.impl;

import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.service.SeckillGoodsService;
import com.atguigu.gmall.activity.util.CacheHelper;
import com.atguigu.gmall.common.config.RedisConfig;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.MD5;
import com.atguigu.gmall.model.activity.OrderRecode;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import sun.dc.pr.PRError;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Service
public class SeckillGoodsServiceImpl implements SeckillGoodsService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    public List<SeckillGoods> findAll() {
        return redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).values();
    }

    @Override
    public SeckillGoods getSeckillGoods(Long skuId) {
        return (SeckillGoods) redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).get(skuId.toString());
    }

    //根据用户和商品ID实现秒杀下单
    @Override
    public void seckillOrder(UserRecode userRecode) {
        //产品状态位， 1：可以秒杀 0：秒杀结束
        String state = (String) CacheHelper.get(userRecode.getSkuId().toString());
        if("0".equals(state)) {
            //已售罄
            return;
        }
        //判断用户是否下单 seckill:user:userId
        Boolean isExist = redisTemplate.opsForValue().setIfAbsent(RedisConst.SECKILL_USER + userRecode.getUserId(), userRecode.getSkuId(), RedisConst.SECKILL__TIMEOUT, TimeUnit.SECONDS);
        if (!isExist){
            return;
        }
        //获取list队列中的商品，如果能够获取，则商品存在，可以下单 seckill:stock:
        String goodsId = (String) redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX + userRecode.getSkuId()).rightPop();
        if (StringUtils.isEmpty(goodsId)){
            //商品售罄，更新状态位  skuId:0  已售空 发布消息 停止秒杀
            redisTemplate.convertAndSend("seckillpush", userRecode.getSkuId()+":0");
        }
        //订单记录
        OrderRecode orderRecode = new OrderRecode();
        orderRecode.setUserId(userRecode.getUserId());
        orderRecode.setSeckillGoods(this.getSeckillGoods(userRecode.getSkuId()));
        orderRecode.setNum(1);
        //预下单接口
        orderRecode.setOrderStr(MD5.encrypt(userRecode.getUserId()+userRecode.getSkuId()));
        //订单数据存入Reids
        redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS).put(orderRecode.getUserId(),orderRecode);
        //更新库存
        this.updateStockCount(orderRecode.getSeckillGoods().getSkuId());
     }


    /**
     * 1.  判断用户是否在缓存中存在
     * 2.  判断用户是否抢单成功
     * 3.  判断用户是否下过订单
     * 4.  判断状态位
     * @param skuId
     * @param userId
     * @return
     */
    @Override
    public Result checkOrder(Long skuId, String userId) {
        //查询redis预下单数据, // 用户在缓存中存在，有机会秒杀到商品
        Boolean isExist = redisTemplate.hasKey(RedisConst.SECKILL_USER + userId);
        if (isExist){
            //判断用户是否正在排队
            //判断用户是否预下单
            Boolean isHasKey = redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS).hasKey(userId);
            if (isHasKey){
                //抢单成功
                OrderRecode  orderRecode = (OrderRecode) redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS).get(userId);
                //秒杀成功
                return Result.build(orderRecode, ResultCodeEnum.SECKILL_SUCCESS);
            }
        }
        //判断是否下单
        Boolean isExistOrder  = redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS_USERS).hasKey(userId);
        if (isExistOrder){
            String orderId = (String) redisTemplate.boundHashOps(RedisConst.SECKILL_ORDERS_USERS).get(userId);
            return Result.build(orderId, ResultCodeEnum.SECKILL_ORDER_SUCCESS);
        }

        //获取状态位
        String  state = (String) CacheHelper.get(skuId.toString());
        if ("0".equals(state)){
            //已售罄 抢单失败
            return Result.build(null, ResultCodeEnum.SECKILL_FAIL);
        }
        //正在排队中
        return Result.build(null, ResultCodeEnum.SECKILL_RUN);
    }

    ////  表示更新mysql -- redis 的库存数据！
    //单机部署就是本地锁 ，集群是分布式锁
    @Transactional(rollbackFor =Exception.class)
    public void updateStockCount(Long skuId) {
        //非集群部署
//          //加锁
//        Lock lock = new ReentrantLock();
//        //上锁
        //集群 分布式锁
        RLock lock = redissonClient.getLock("lock:" + skuId);
        lock.lock();
        try {
            //  获取到存储库存剩余数！
            //  key = seckill:stock:46
            String stockKey = RedisConst.SECKILL_STOCK_PREFIX+ skuId;
            //计算当前商品剩余数量
            Long count = redisTemplate.boundListOps(stockKey).size();
            if (count%2==0){
                //开始更新数据
                SeckillGoods seckillGoods = getSeckillGoods(skuId);
                //  赋值剩余库存数！
                seckillGoods.setStockCount(count.intValue());
                //  更新的数据库！
                seckillGoodsMapper.updateById(seckillGoods);
                //  更新缓存！
                redisTemplate.boundHashOps(RedisConst.SECKILL_GOODS).put(skuId.toString(),seckillGoods);
            }
        }catch (Exception e){
          e.printStackTrace();
        } finally {
            //  解锁！
            lock.unlock();
        }
    }
}
